/**
 * Vue 固定区域拖拽指令
 * 基于 DragHelper 类的设计思想重新实现
 * 使用方法: v-drag
 * 功能: 在父容器内拖拽元素，支持鼠标和触摸操作
 */

class DragHelper {
  constructor(element, options = {}) {
    this.element = element;
    this.options = {
      // 是否限制在父元素内
      constrainToParent: true,
      // 拖拽开始时的回调
      onStart: null,
      // 拖拽过程中的回调
      onMove: null,
      // 拖拽结束时的回调
      onEnd: null,
      ...options
    };
    
    this.isDragging = false;
    this.startX = 0;
    this.startY = 0;
    this.initialX = 0;
    this.initialY = 0;
    
    this.init();
  }
  
  init() {
    if (!this.element) {
      throw new Error('拖拽元素不能为空');
    }
    
    // 设置元素样式
    this.element.style.position = 'absolute';
    this.element.style.cursor = 'move';
    this.element.style.userSelect = 'none';
    
    // 绑定事件
    this.bindEvents();
    
    // 设置初始位置
    this.updatePosition();
  }
  
  bindEvents() {
    this.element.addEventListener('mousedown', this.onMouseDown.bind(this));
    document.addEventListener('mousemove', this.onMouseMove.bind(this));
    document.addEventListener('mouseup', this.onMouseUp.bind(this));
    
    // 触摸事件支持
    this.element.addEventListener('touchstart', this.onTouchStart.bind(this), { passive: false });
    document.addEventListener('touchmove', this.onTouchMove.bind(this), { passive: false });
    document.addEventListener('touchend', this.onTouchEnd.bind(this));
  }
  
  onMouseDown(e) {
    e.preventDefault();
    this.startDrag(e.clientX, e.clientY);
  }
  
  onTouchStart(e) {
    e.preventDefault();
    const touch = e.touches[0];
    this.startDrag(touch.clientX, touch.clientY);
  }
  
  startDrag(clientX, clientY) {
    this.isDragging = true;
    this.startX = clientX;
    this.startY = clientY;
    
    // 获取元素当前位置（相对于父元素）
    const rect = this.element.getBoundingClientRect();
    const parentRect = this.element.parentElement ? this.element.parentElement.getBoundingClientRect() : { left: 0, top: 0 };
    this.initialX = rect.left - parentRect.left;
    this.initialY = rect.top - parentRect.top;
    
    // 添加拖拽样式
    this.element.classList.add('v-drag-dragging');
    
    // 触发开始回调
    if (this.options.onStart) {
      this.options.onStart({
        element: this.element,
        x: this.initialX,
        y: this.initialY
      });
    }
  }
  
  onMouseMove(e) {
    if (!this.isDragging) return;
    
    e.preventDefault();
    this.updateDrag(e.clientX, e.clientY);
  }
  
  onTouchMove(e) {
    if (!this.isDragging) return;
    
    e.preventDefault();
    const touch = e.touches[0];
    this.updateDrag(touch.clientX, touch.clientY);
  }
  
  updateDrag(clientX, clientY) {
    if (!this.isDragging) return;
    
    const deltaX = clientX - this.startX;
    const deltaY = clientY - this.startY;
    
    let newX = this.initialX + deltaX;
    let newY = this.initialY + deltaY;
    
    // 应用边界限制
    const boundary = this.getBoundary();
    
    // 确保元素不会超出边界
    newX = Math.max(boundary.left, Math.min(boundary.right, newX));
    newY = Math.max(boundary.top, Math.min(boundary.bottom, newY));
    
    // 更新元素位置
    this.element.style.left = newX + 'px';
    this.element.style.top = newY + 'px';
    
    // 触发移动回调
    if (this.options.onMove) {
      this.options.onMove({
        element: this.element,
        x: newX,
        y: newY,
        deltaX,
        deltaY
      });
    }
  }
  
  onMouseUp(e) {
    if (!this.isDragging) return;
    
    this.endDrag();
  }
  
  onTouchEnd(e) {
    if (!this.isDragging) return;
    
    this.endDrag();
  }
  
  endDrag() {
    this.isDragging = false;
    
    // 移除拖拽样式
    this.element.classList.remove('v-drag-dragging');
    
    // 触发结束回调
    if (this.options.onEnd) {
      const rect = this.element.getBoundingClientRect();
      const parentRect = this.element.parentElement ? this.element.parentElement.getBoundingClientRect() : { left: 0, top: 0 };
      this.options.onEnd({
        element: this.element,
        x: rect.left - parentRect.left,
        y: rect.top - parentRect.top
      });
    }
  }
  
  getBoundary() {
    let boundary = { left: 0, top: 0, right: window.innerWidth, bottom: window.innerHeight };
    
    // 如果限制在父元素内
    if (this.options.constrainToParent && this.element.parentElement) {
      const parent = this.element.parentElement;
      
      // 获取容器的实际内容区域（包括边框和padding）
      const parentRect = parent.getBoundingClientRect();
      const parentStyle = window.getComputedStyle(parent);
      
      // 获取边框宽度
      const borderLeft = parseFloat(parentStyle.borderLeftWidth) || 0;
      const borderRight = parseFloat(parentStyle.borderRightWidth) || 0;
      const borderTop = parseFloat(parentStyle.borderTopWidth) || 0;
      const borderBottom = parseFloat(parentStyle.borderBottomWidth) || 0;
      
      // 获取padding
      const paddingLeft = parseFloat(parentStyle.paddingLeft) || 0;
      const paddingRight = parseFloat(parentStyle.paddingRight) || 0;
      const paddingTop = parseFloat(parentStyle.paddingTop) || 0;
      const paddingBottom = parseFloat(parentStyle.paddingBottom) || 0;
      
      // 计算实际可用的内容区域
      // 注意：getBoundingClientRect()返回的是包含边框的尺寸
      // 所以我们需要减去边框和padding来得到实际内容区域
      const availableWidth = parentRect.width - borderLeft - borderRight - paddingLeft - paddingRight;
      const availableHeight = parentRect.height - borderTop - borderBottom - paddingTop - paddingBottom;
      
      // 获取元素尺寸（包含边框和padding）
      const elementRect = this.element.getBoundingClientRect();
      const elementWidth = elementRect.width;
      const elementHeight = elementRect.height;
      
      // 计算元素可以移动的最大位置
      // 元素可以移动的范围是：从0到(可用宽度 - 元素宽度)
      const maxRight = Math.max(0, availableWidth - elementWidth);
      const maxBottom = Math.max(0, availableHeight - elementHeight);
      
      // 考虑padding，元素的实际移动范围应该从padding开始
      boundary = {
        left: paddingLeft,
        top: paddingTop,
        right: maxRight + paddingLeft,
        bottom: maxBottom + paddingTop
      };
      
      // 调试信息（开发时可用）
      if (process.env.NODE_ENV === 'development') {
        console.log('边界计算:', {
          parentRect: { width: parentRect.width, height: parentRect.height },
          available: { width: availableWidth, height: availableHeight },
          element: { width: elementWidth, height: elementHeight },
          boundary: boundary
        });
      }
    }
    
    return boundary;
  }
  
  // 更新位置
  updatePosition() {
    const rect = this.element.getBoundingClientRect();
    const parentRect = this.element.parentElement ? this.element.parentElement.getBoundingClientRect() : { left: 0, top: 0 };
    const relativeX = rect.left - parentRect.left;
    const relativeY = rect.top - parentRect.top;
    this.element.style.left = relativeX + 'px';
    this.element.style.top = relativeY + 'px';
  }
  
  // 销毁拖拽功能
  destroy() {
    this.element.removeEventListener('mousedown', this.onMouseDown);
    document.removeEventListener('mousemove', this.onMouseMove);
    document.removeEventListener('mouseup', this.onMouseUp);
    
    this.element.removeEventListener('touchstart', this.onTouchStart);
    document.removeEventListener('touchmove', this.onTouchMove);
    document.removeEventListener('touchend', this.onTouchEnd);
    
    // 清理样式
    this.element.classList.remove('v-drag-element', 'v-drag-dragging');
  }
}

// 指令定义
export const drag = {
  mounted(el, binding) {
    // 获取指令参数
    const options = binding.value || {};
    
    // 创建拖拽实例
    const dragInstance = new DragHelper(el, {
      constrainToParent: true,
      ...options
    });
    
    // 将实例存储在元素上
    el._dragInstance = dragInstance;
    
    // 添加基础样式类
    el.classList.add('v-drag-element');
  },
  
  unmounted(el) {
    // 销毁拖拽实例
    if (el._dragInstance) {
      el._dragInstance.destroy();
      delete el._dragInstance;
    }
    
    // 清理样式类
    el.classList.remove('v-drag-element', 'v-drag-dragging');
  }
}

// 默认导出
export default drag